松本行弘的程序世界 7 文字编码

文字编码的种类

早期的文字编码

纸带与文字的表现

文字是什么

走向英语以外的语言(欧洲篇)

英语以外得到语言(亚洲篇)

Unicode的问世

统一编码成16位的汉字统合

Unicode的两个问题

选择16位文字的Unicode有两大副作用。一是字节顺序的问题,一是NUL文字问题。
字节顺序就是低八位先放还是高八位先放的问题。
传统C语言处理的字符串,一般有一个终端文字NUL(‘\0’)。但是作为16位文字的字符串,中途会出现NUL文字。所以,C语言中处理字符串的传统函数不能用于16位文字的字符串。
像java那样的语言,一开始就是以16位文字为前提而设计的,所以没什么问题。但以C语言处理16位文字的时候,需要全新的api。

Unicode的文字集

现在,Unicode放弃了16位方式,而用21位来表示一个文字,现在Unicode能够表示4111个文字,肯定够用了。

文字表示的不确定性

Unicode的字符编码方式

UTF-8

UTF-8以一定式样的字节组合来表示Unicode中的21位文字。对于内部程序处理字符串非常方便,另外没有字节顺序问题,在外部处理时也很有用。
缺点:消费过多内存,几乎所有的汉字都要占用3个字节。
构成文字的字节数是可变的,随机访问任意文字,代价与字符串长度成正比。
但是随着计算机内存的容量和性能提高,这些缺点也无所谓了。

UTF-16

Unicode中能以16位表示的空间就以16位表示,超过16位就以两个16位码组合来表示。到现在缺点已经很突出了,从今以后没必要采用这种字符编码方式了。

UTF-32

固定长,可以随机访问,但存在字节顺序的问题。
因为4字节,没什么人气。

程序中的文字处理

文字编码有多个意思

只能处理文字集中包含的文字

纷繁复杂的文字编码方式

影响力渐微的Shift_JIS与EUC-JP

Unicode有多种字符编码方式

为什么会发生乱码

字符编码方式错误

没有字体

变换为内部码时出错

发生不完全变换

文字集的不同

字节顺序错误

像UTF-16,UTF-32这种基本数据单位大于一个字节的编码方式,存放数据时字节该以什么顺序摆放,有两大流派,一个是big endian,一个是little endian。所以同样是UTF-16格式(UTF-32也一样)根据字节顺序不同就会有两种。
UTF-8就不会。

从编程语言的角度处理文字

编程语言处理文本数据的方法,有UCS方式和CSI方式两种。

以变换为前提的UCS方式

UCS(泛用字符集),是指程序中所处理的共同文字集(及字符编码方式)。输入输出时,编程语言将文本数据变成UCS,内部对文本数据进行统一处理。优点:

  1. 原理简单,容易实现
  2. 除变换外,处理成本低
  3. 实际成果多

缺点:

  1. 发生不必要的变换
  2. 变换存在模糊部分
  3. 有外字及机种依存文字的问题
  4. UCS中不包含的文字绝对不能处理

原封不动处理的CSI方式

CSI(Character Set Independent,字符集独立),是指不对各种文字集(及编码方式)进行任何变换,原封不动地进行处理。相对于UCS的内部只有一种编码方式的处理方式,CSI中对各种编码方式原封不动地处理。
CSI是优点多,自由度高的方式。

  1. 不发生不必要的变换
  2. 不发生变换所带来的问题
  3. 不易发生外字的问题。
  4. 理论上不存在不能处理的文字
  5. 根据需要,可以处理应用程序独立的文字集

缺点:

  1. 字符串的处理容易变得复杂化
  2. 预计处理性能会变低
  3. 实际成果少

实际上,现在存在的多种编程语言中,采用CSI方式的几乎没有。

使用UTF-16的Java

Java采用UCS方式,内部字符编码选用UTF-16
制作Java时,Unicode仅限于16位。java没选择可变长的UTF-8,而选择UTF-16,因而产生了这样的悲剧。说是时机的恶作剧也罢,真是太可惜了。

使用UTF-8的Perl

Perl也使用UCS方式,内部编码方式采用UTF-8。

用UTF-16的Python

UCS,UTF-16

采用CSI方式的Ruby1.8

强化了功能的Ruby1.9

是UCS还是CSI